package org.qydjk.common.dao.impl;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.qydjk.common.dao.IBaseDao;
import org.qydjk.common.util.BeanMapUtil;
import org.qydjk.common.util.ListUtil;
import org.qydjk.common.vo.HibernatePage;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public class BaseDao extends HibernateDaoSupport implements IBaseDao {


    public <T> Serializable save(T t) throws Exception {
        return getHibernateTemplate().save(t);
    }

    public <T> void update(T t) throws Exception {
        getHibernateTemplate().update(t);
        getHibernateTemplate().flush();
    }

    public <T> void delete(T t) throws Exception {
        getHibernateTemplate().delete(t);
        getHibernateTemplate().flush();
    }

    public <T> void deleteAll(Collection<T> ts) throws Exception {
        getHibernateTemplate().deleteAll(ts);
        getHibernateTemplate().flush();
    }

    public <T> void saveOrUpdate(T t) throws Exception {
        getHibernateTemplate().saveOrUpdate(t);
        getHibernateTemplate().flush();
    }

    /**
     * 当调用load()方法的时候会返回一个目标对象的代理对象，在这个代理对象中只存储了目标对象的ID值，只有当调用除ID值以外的属性值的时候才会发出SQL查询的
     * @param t
     * @param id
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T load(Class<T> t, Serializable id) throws Exception {
        return getHibernateTemplate().load(t,id);
    }

    /**
     * 当get()方法被调用的时候就会立即发出SQL语句进行查询
     * @param t
     * @param id
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T get(Class<T> t, Serializable id) throws Exception {
        return getHibernateTemplate().get(t,id);
    }

    public <T> List<T> findByHql(String hql, Object... values) throws Exception {
        return (List<T>) getHibernateTemplate().find(hql,values);
    }

    public <T> List<T> findByHql(final String hql, final HibernatePage pager, final Object... values) throws Exception {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback<T>() {
            public T doInHibernate(Session session) throws HibernateException {
                Query query = session.createQuery(hql);
                for(int i = 0;i < values.length;i++){
                    query.setParameter(i, values[i]);
                }
                if(pager != null){
                    query.setFirstResult(pager.getStart()).setMaxResults(pager.getPageSize());
                }
                return (T) query.list();
            }
        });
    }

    public <T> List<T> findByExample(T t) throws Exception {
        return (List<T>) getHibernateTemplate().findByExample(t);
    }

    public <T> List<T> findBySQL(final String sql, final Class<?> cls, final Object... values) throws Exception{
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback<T>() {
            public T doInHibernate(Session session) throws HibernateException {
                SQLQuery query = session.createSQLQuery(sql);
                query.addEntity(cls);
                if(values != null){
                    for(int i = 0;i < values.length;i++){
                        query.setParameter(i, values[i]);
                    }
                }
                return (T) query.list();
            }
        });
    }

    public <T> List<T> findBySQL(final String sql, final Class<?> cls, final HibernatePage pager, final Object... values) throws Exception{
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback<T>() {
            public T doInHibernate(Session session) throws HibernateException {
                SQLQuery query = session.createSQLQuery(sql);
                query.addEntity(cls);
                if(values != null){
                    for(int i = 0;i < values.length;i++){
                        query.setParameter(i, values[i]);
                    }
                }
                if(pager != null){
                    query.setFirstResult(pager.getStart()).setMaxResults(pager.getPageSize());
                }
                return (T) query.list();
            }
        });
    }

    public List<Map<String,Object>> findMapBySQL(final String sql, final Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<List<Map<String,Object>>>() {
            public List<Map<String,Object>> doInHibernate(Session session) throws HibernateException {
                SQLQuery query = session.createSQLQuery(sql);
                query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
                if(values != null){
                    for(int i = 0;i < values.length;i++){
                        query.setParameter(i, values[i]);
                    }
                }
                return query.list();
            }
        });
    }

    public List<Map<String,Object>> findMapBySQL(final String sql, final HibernatePage pager, final Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<List<Map<String,Object>>>() {
            public List<Map<String,Object>> doInHibernate(Session session) throws HibernateException {
                SQLQuery query = session.createSQLQuery(sql);
                query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
                if(values != null){
                    for(int i = 0;i < values.length;i++){
                        query.setParameter(i, values[i]);
                    }
                }
                if(pager != null){
                    query.setFirstResult(pager.getStart()).setMaxResults(pager.getPageSize());
                }
                return query.list();
            }
        });
    }

    public int excuteSQL(final String sql) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<Integer>() {
            public Integer doInHibernate(Session session) throws HibernateException {
                return session.createSQLQuery(sql).executeUpdate();
            }
        });
    }

    public int excuteHQL(final String hql) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<Integer>() {
            public Integer doInHibernate(Session session) throws HibernateException {
                return session.createQuery(hql).executeUpdate();
            }
        });
    }

    public int getRecordCountHQL(final String hql, final Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<Integer>() {
            public Integer doInHibernate(Session session) throws HibernateException {
                Query query = session.createQuery(hql);
                for(int i = 0;i < values.length;i++){
                    query.setParameter(i, values[i]);
                }
                return ((Number)query.uniqueResult()).intValue();
            }
        });
    }

    public int getRecordCountSQL(final String sql, final Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<Integer>() {
            public Integer doInHibernate(Session session) throws HibernateException {
                Query query = session.createSQLQuery(sql);
                for(int i = 0;i < values.length;i++){
                    query.setParameter(i, values[i]);
                }
                return ((Number)query.uniqueResult()).intValue();
            }
        });
    }

    public <T> T getUniqueResultHQL(final String hql, final Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<T>() {
            public T doInHibernate(Session session) throws HibernateException {
                Query query = session.createQuery(hql);
                for(int i = 0;i < values.length;i++){
                    query.setParameter(i, values[i]);
                }
                return (T) query.uniqueResult();
            }
        });
    }

    public <T> T getUniqueResultSQL(final String sql, final Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<T>() {
            public T doInHibernate(Session session) throws HibernateException {
                Query query = session.createSQLQuery(sql);
                for(int i = 0;i < values.length;i++){
                    query.setParameter(i, values[i]);
                }
                return (T) query.uniqueResult();
            }
        });
    }

    public List<List<Object>> findSingleColumnListBySQL(String sql, Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<List<List<Object>>>() {
            public List<List<Object>> doInHibernate(Session session) throws HibernateException {
                SQLQuery query = session.createSQLQuery(sql);
                query.setResultTransformer(Transformers.TO_LIST);
                if(values != null){
                    for(int i = 0;i < values.length;i++){
                        query.setParameter(i, values[i]);
                    }
                }
                return query.list();
            }
        });
    }

    public List<List<Object>> findSingleColumnListBySQL(String sql, HibernatePage pager, Object... values) throws Exception{
        return getHibernateTemplate().execute(new HibernateCallback<List<List<Object>>>() {
            public List<List<Object>> doInHibernate(Session session) throws HibernateException {
                SQLQuery query = session.createSQLQuery(sql);
                query.setResultTransformer(Transformers.TO_LIST);
                if(values != null){
                    for(int i = 0;i < values.length;i++){
                        query.setParameter(i, values[i]);
                    }
                }
                if(pager != null){
                    query.setFirstResult(pager.getStart()).setMaxResults(pager.getPageSize());
                }
                return query.list();
            }
        });
    }

    public <T> T findSingleBySQL(String sql, Class<?> cls, Object... values) throws Exception {
        List<Map<String,Object>> resMap = this.findMapBySQL(sql, values);
        if(resMap != null && resMap.size() > 0){
            List<T> list = (List<T>) BeanMapUtil.map2Java(cls, resMap, true);
            return list.get(0);
        }
        return null;
    }

    public <T> T findSingleByHql(String hql, Object... values) throws Exception {
        List<T> list = this.findByHql(hql,values);
        if(!ListUtil.isNullOrEmpty(list)){
            return list.get(0);
        }
        return null;
    }

    public <T> List<T> findBeanBySQL(String sql, Class<?> cls, Object... values) throws Exception {
        return (List<T>) BeanMapUtil.map2Java(cls,findMapBySQL(sql,values),true);
    }

    public <T> T findSingleBeanBySQL(String sql, Class<?> cls, Object... values) throws Exception {
        return findSingleBySQL(sql,cls,values);
    }

    public <T> List<T> findBeanBySQL(String sql, Class<?> cls, HibernatePage pager, Object... values) throws Exception {
        return (List<T>) BeanMapUtil.map2Java(cls,findMapBySQL(sql,pager,values),true);
    }
}